package org.aksw.xoperator.aiml;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aksw.xoperator.Constants;
import org.aksw.xoperator.sparql.SparqlResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

public class SPARQLResultTableWrapper {

	

	private static Log log = LogFactory.getLog(SPARQLResultTableWrapper.class);

	private Document doc;
	
	private SparqlResult result;

	public SPARQLResultTableWrapper(SparqlResult result) {


		try {
			this.result = result;
			if(result.getAnswer()!=null&&!result.getAnswer().isEmpty())
			doc = new SAXBuilder().build(new StringReader(result.getAnswer()));
			log.info("Wrapping: " + result.getAnswer());

		} catch (Exception e) {
			log.error("Unable to read the result", e);
		}
	}

	public Document getDoc() {
		return doc;
	}

	public List<String> getHeadlines() {
		List<String> headlines = new ArrayList<String>();
		try {
			XPath xpath = XPath.newInstance("/res:sparql/res:head/res:variable/@name");
			xpath.addNamespace(Constants.HTTP_WWW_W3_ORG_2005_SPARQL_RESULTS);
			List matches = xpath.selectNodes(doc);
			for (Object object : matches) {
				Attribute attrib = (Attribute) object;
				headlines.add(attrib.getValue());
			}

			
		} catch (Exception e) {
			log.error("Error xpathing: ", e);
		}
		return headlines;
	}
	
	
	public List<String> getResultColumnAsStrings(String headline){
		List<Element> results = getResultColumnAsElements(headline); 
		List<String> stringResults = new ArrayList<String>();
		
		for (Element resultElement : results) {
			stringResults.add(resultElement.getText());
		}
		return stringResults;
		
		
		
	}
	public List<Element> getResultColumnAsElements(String headline){
		List<Element> results = new ArrayList<Element>();
		try {
			XPath xpath = XPath.newInstance("/res:sparql/res:results/res:result/res:binding/*[../@name='"+headline+"']");
			xpath.addNamespace(Constants.HTTP_WWW_W3_ORG_2005_SPARQL_RESULTS);
			List matches = xpath.selectNodes(doc);
			for (Object object : matches) {
				results.add((Element) object);
			}

			
		} catch (Exception e) {
			log.error("Error xpathing: ", e);
		}
		return results;
	}
	/**
	 * Transforms the result set into easily accessible objects. Each row is represented in the List object as a map, in which for every headline used as key, the corresponding value can be found
	 * @return
	 */
	public List<Map<String, String>>  getResultRows(){
		
		List<Map<String, String>>  toReturn = getResultRow(true);
		log.info("returning: " + toReturn.size());
		return toReturn;
		
		
	}
	
	
	public List<Map<String, Element>> getResultRowsElments(){
		
		return getResultRow(false);
	}
	
	
	private List getResultRow(boolean asString){
		List<Map<String, Object>> result = new ArrayList<Map<String,Object>>();
		
		try {
			XPath xpath = XPath.newInstance("/res:sparql/res:results/res:result");
			xpath.addNamespace(org.aksw.xoperator.Constants.HTTP_WWW_W3_ORG_2005_SPARQL_RESULTS);
			List<Element> results = xpath.selectNodes(doc);
			for (Element resultElement : results) {
				Map<String, Object> row = new HashMap<String, Object>();
				List<Element> bindings =  resultElement.getChildren("binding", Constants.HTTP_WWW_W3_ORG_2005_SPARQL_RESULTS);
				for (Element element : bindings) {
					row.put(element.getAttribute("name").getValue(),asString?((Element)element.getChildren().get(0)).getText():element.getChildren().get(0));
				}
				result.add(row);
			}
			 

			
		} catch (Exception e) {
			log.error("Error xpathing: ", e);
		}
		
		return result;
		
	}
	
	
	public int getResultCount(){
		int count  =0;
		try {
			XPath xpath = XPath.newInstance("count(/res:sparql/res:results/res:result)");
			xpath.addNamespace(Constants.HTTP_WWW_W3_ORG_2005_SPARQL_RESULTS);
			count = xpath.numberValueOf(doc).intValue();
			 

			
		} catch (Exception e) {
			log.error("Error xpathing: ", e);
		}
		return count;
		
	}
	
	public String getStoreName(){
		
		return result.getAnsweredBy().getName();
		
	}
	
	public String getErrors(){
		return this.result.getErrorMsg();
	}
	
}
